package tr.edu.metu.is.mega.server.business;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import tr.edu.metu.is.mega.client.resource.MegaConstants;
import tr.edu.metu.is.mega.common.dto.ActivityType;
import tr.edu.metu.is.mega.common.dto.ReviewerDTO;
import tr.edu.metu.is.mega.common.dto.SubmissionDTO;
import tr.edu.metu.is.mega.common.dto.SubmissionViewDTO;
import tr.edu.metu.is.mega.common.dto.TeamDTO;
import tr.edu.metu.is.mega.common.dto.UserRole;
import tr.edu.metu.is.mega.server.core.ZipDTO;
import tr.edu.metu.is.mega.server.dao.ActivityDAO;
import tr.edu.metu.is.mega.server.dao.ReviewerDAO;
import tr.edu.metu.is.mega.server.dao.SubmissionDAO;
import tr.edu.metu.is.mega.server.dao.SubmissionViewDAO;
import tr.edu.metu.is.mega.server.dao.TeamDAO;
import tr.edu.metu.is.mega.server.dao.UserDAO;
import tr.edu.metu.is.mega.server.entity.Activity;
import tr.edu.metu.is.mega.server.entity.Course;
import tr.edu.metu.is.mega.server.entity.Reviewer;
import tr.edu.metu.is.mega.server.entity.Submission;
import tr.edu.metu.is.mega.server.entity.Submissionrevision;
import tr.edu.metu.is.mega.server.entity.Team;
import tr.edu.metu.is.mega.server.entity.Teammember;

/**
 * Class to manage schedule templates.
 */
public class SubmissionViewManager {

    private final SubmissionViewDAO dao;

    private final UserDAO userDAO;

    private final ActivityDAO activityDAO;

    private final TeamDAO teamDAO;

    private final ReviewerDAO reviewerDAO;

    private final SubmissionDAO submissionDAO;

    /**
     * Default constructor.
     */
    public SubmissionViewManager() {
        dao = new SubmissionViewDAO();
        userDAO = new UserDAO();
        activityDAO = new ActivityDAO();
        teamDAO = new TeamDAO();
        reviewerDAO = new ReviewerDAO();
        submissionDAO = new SubmissionDAO();
    }

    /**
     * Queries submissions with given courseid and teamid.
     * 
     * @param role
     * 
     * @param courseid course
     * @param teamid team
     * @return list of submission view
     */
    public List<SubmissionViewDTO> getSubmissions(UserRole role, int courseid, int teamid) {
        List<SubmissionViewDTO> submissions = dao.querySubmissions(courseid, teamid);
        return submissions;
    }

    /**
     */
    public String downloadAll(UserRole role, int courseid, int teamid) {
        List<SubmissionViewDTO> submissions;
        if (role == UserRole.STUDENT) {
            submissions = dao.querySubmissions(courseid, teamid);
        } else {
            Team team = new Team();
            Course course = new Course();
            course.setPkid(courseid);
            team.setCourse(course);
            List<Team> list = teamDAO.findByExample(team, false);
            submissions = new ArrayList<SubmissionViewDTO>();
            for (Team team2 : list) {
                submissions.addAll(dao.querySubmissions(courseid, team2.getPkid()));
            }
        }
        List<ZipDTO> zipDTOs = new ArrayList<ZipDTO>();
        for (SubmissionViewDTO dto : submissions) {
            if (dto.getSubmissionfile() != null) {
                String path = MegaConstants.DEPLOY_PATH + MegaConstants.TEAM_PATH + dto.getTeamid() + "/submission/" + dto.getSubmissionfile();
                ZipDTO zipDTO = new ZipDTO();
                zipDTO.setFilePath(path);
                zipDTO.setZipBase(dto.getTeamname() + "/");
                if (!zipDTOs.contains(zipDTO)) {
                    zipDTOs.add(zipDTO);
                }
            }
        }
        String zipPath = MegaConstants.ZIP_PATH + System.currentTimeMillis() + ".zip";
        try {
            ZipUtil.createZip(zipDTOs, MegaConstants.DEPLOY_PATH + zipPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return zipPath;
    }

    /**
     * Submission upload helper.
     * 
     * @param view view dto
     * @return updated view
     */
    public void uploadSubmission(SubmissionDTO dto) throws Exception {
        Submission submission;
        if (dto.getPkid() != null && dto.getPkid() > 0) {
            submission = submissionDAO.findById(dto.getPkid());
            if (submission.getSubmissionrevisions() == null) {
                submission.setSubmissionrevisions(new ArrayList<Submissionrevision>(1));
            }
            Submissionrevision revision = new Submissionrevision();
            revision.setFilepath(submission.getFilepath());
            revision.setSubmittedby(submission.getSystemuser().getName() + " " + submission.getSystemuser().getSurname());
            revision.setSubmission(submission);
            revision.setSubmissiondate(submission.getSubmissiondate());
            submission.getSubmissionrevisions().add(revision);

        } else {
            submission = new Submission();
            submission.setActivity(activityDAO.findById(dto.getActivity()));
            submission.setTeam(teamDAO.findById(dto.getTeam().getPkid()));
        }
        submission.setFilepath(dto.getFilepath());
        // if it is a review activity set reviewed submission as related
        // submission
        if (submission.getActivity().getSubmissiontype().equals(ActivityType.REVIEW.getCode())) {
            Reviewer reviewerFilter = new Reviewer();
            Team team = new Team();
            team.setPkid(submission.getTeam().getPkid());
            reviewerFilter.setReviewerTeam(team);
            Activity activity = new Activity();
            activity.setPkid(submission.getActivity().getPkid());
            reviewerFilter.setReviewActivity(activity);
            List<Reviewer> reviewerRecords = reviewerDAO.findByExample(reviewerFilter, false);
            if (reviewerRecords.size() != 1) {
                throw new Exception("Your team is not assigned to review a team for this activity.");
            }
            Reviewer reviewer = reviewerRecords.get(0);
            // find submission of other team
            Submission submissionFilter = new Submission();
            team.setPkid(reviewer.getTeam().getPkid());
            submissionFilter.setTeam(team);
            activity.setPkid(reviewer.getActivity().getPkid());
            submissionFilter.setActivity(activity);
            List<Submission> submissions = submissionDAO.findByExample(submissionFilter, false);
            if (submissions.size() != 1) {
                throw new Exception("Other team has not uploaded work product to review yet!");
            }
            submission.setFkRelatedsubmission(submissions.get(0).getPkid());

        }

        submission.setSystemuser(userDAO.findById(dto.getSystemuser().getPkid()));
        submission.setSubmissiondate(new Timestamp(dto.getSubmissiondate().getTime()));

        submission = submissionDAO.update(submission);

        // send mail to reviewer team
        Reviewer reviewerFilter = new Reviewer();
        reviewerFilter.setTeam(submission.getTeam());
        reviewerFilter.setActivity(submission.getActivity());
        List<Reviewer> list = reviewerDAO.findByExample(reviewerFilter, false);
        if (list.size() == 1) {
            Team reviewTeam = list.get(0).getReviewerTeam();
            for (Teammember teammember : reviewTeam.getTeammembers()) {
                MailService.submissionMailer(teammember.getCoursestudent().getSystemuser().getEmail(), dto);
            }
        }
        dao.getEntityManager().clear();
    }

    /**
     * Assign reviewer helper.
     * 
     * @param view view dto
     */
    public void assignReviewer(ReviewerDTO dto) {
        Reviewer example = new Reviewer();
        Activity activity = new Activity();
        activity.setPkid(dto.getActivity());
        example.setActivity(activity);
        Team team = new Team();
        team.setPkid(dto.getTeam().getPkid());
        example.setTeam(team);
        List<Reviewer> list = reviewerDAO.findByExample(example, false);
        Reviewer reviewer = null;
        if (list.size() == 1) {
            reviewer = list.get(0);
        } else {
            reviewer = new Reviewer();
            reviewer.setActivity(activityDAO.findById(dto.getActivity()));
            reviewer.setTeam(teamDAO.findById(dto.getTeam().getPkid()));
        }
        reviewer.setReviewerTeam(teamDAO.findById(dto.getReviewerTeam().getPkid()));
        reviewer.setReviewActivity(activityDAO.findById(dto.getReviewActivity()));
        reviewerDAO.update(reviewer);

        for (Teammember teammember : reviewer.getTeam().getTeammembers()) {
            MailService.reviewMailer(teammember.getCoursestudent().getSystemuser().getEmail(), dto);
        }

        dao.getEntityManager().clear();
    }

    public List<SubmissionDTO> querySubmissionsToReview(int reviewerTeam) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("reviewerTeam", reviewerTeam);
        List<Submission> entities = submissionDAO.findByNamedQuery("querySubmissionsToReview", params);
        List<SubmissionDTO> list = new ArrayList<SubmissionDTO>();
        for (Submission s : entities) {
            SubmissionDTO dto = new SubmissionDTO();
            dto.setFilepath(s.getFilepath());
            TeamDTO team = new TeamDTO();
            team.setPkid(s.getTeam().getPkid());
            team.setTeamName(s.getTeam().getTeamname());
            dto.setTeam(team);
            dto.setSubmissiondate(s.getSubmissiondate());
            dto.setActivity(s.getActivity().getPkid());
            dto.setActivityDescription(s.getActivity().getDescription());
            list.add(dto);
        }
        return list;

    }
}
